package org.dxw.common.config;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.dxw.common.ano.Val;
import org.reflections.Reflections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @description:
 * @warning 要配置包扫描路径 configClzScanPacks
 * eg：
 *
 * @Val(preFix = "dxw.utop")
 * public class UtopProperties extends AppConfigProperties {
 *
 *     public static String url;
 *
 *     public static String userName;
 *
 *     public static String passWord;
 *
 *     @Val("time-out")
 *     public static Integer timeOut;
 *
 * }
 *
 * @author: dxw
 * @create: 2022-03-12 21:17
 **/
@Slf4j
@Component
public class AppConfigProperties implements ApplicationRunner {

    @Autowired
    private ConfigurableEnvironment environment;

    private List<Class> configClz = new ArrayList<>();

    /**
     * 多个包路径用逗号隔开
     */
    private static String configClzScanPacks = "org.dxw.constant";

    /**
     * 加上final， 避免子类子类重写
     */
    @Override
    public final void run(ApplicationArguments args) throws Exception {
        log.info("从环境中读取配置注入变量...");
        initConfigClz();
        log.info("配置类：{}", JSON.toJSONString(configClz));
        for (Class clz : configClz) {
            Val clzVal = (Val)clz.getAnnotation(Val.class);
            String preFix = clzVal == null ? "" : clzVal.preFix() + ".";
            Field[] fields = clz.getDeclaredFields();
            if(fields==null || fields.length==0) continue;
            for (Field field : fields) {
                Val annotation = field.getAnnotation(Val.class);
                String name;
                String defVal = null;
                if(annotation !=null){
                    name = StrUtil.isBlank(annotation.name())?annotation.value():annotation.name();
                    defVal = annotation.defVal();
                }else{
                    name = field.getName();
                }
                String property = environment.getProperty(preFix + name);
                if(property == null || property.trim().equals("") || property.equals("null")) property = defVal;
                field.setAccessible(true);
                field.set(null, Convert.convert(field.getType(), property));
            }
        }
    }

    private void initConfigClz(){
        String[] split = configClzScanPacks.split(",");
        for (String s : split) {
            Reflections reflections = new Reflections(s.trim());
            Set<Class<? extends AppConfigProperties>> subTypesOf = reflections.getSubTypesOf(AppConfigProperties.class);
            subTypesOf.forEach(x -> configClz.add(x));
        }
    }

}